//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler execution subsystem
// FILE:            XortElement.cpp - support of XNIVariant in XortElement
// AUTHOR:          Vladimir Gumenuk
// DATE:            22-Aug-2014
// MODIFICATIONS:
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "xort.h"
#include "xruntime.h"
#include "XortString.h"

int XortElement::InitFromXNIVariant( const XNIVariant& vVal, symbolref pSymType, XRuntime *pRuntime )
{
    int iRet = XORT_OK;

    switch( vVal.bType )
    {
    case xni_v:
    case xni_s1:
    case xni_u1:
    case xni_s2:
    case xni_u2:
    case xni_s4:
    case xni_u4:
    case xni_s8:
    case xni_u8:
    case xni_r4:
    case xni_r8:
        bType = vVal.bType;
        _u8 = vVal._u8;
        break;

    case xni_ptr:
        {
            bType = t_p;
            
            XortNativeInterface *pObj = (XortNativeInterface *)vVal._p;
            if( pObj )
            {
                if( pSymType->m_csName.Compare( pObj->GetName() ) != 0 )
                    return ERR_INVALID_OBJECT_NAME;
                
                xobject *pXOBJ = NULL;
                iRet = pRuntime->createXObject( *pSymType, pObj, &pXOBJ );
                if( iRet == XORT_OK )
                {
                    SetValue( pXOBJ );
                    pXOBJ->Release();
                }
            }
        }
        break;

    case xni_str:
        {
            if( pSymType->m_dwType != t_string )
                return ERR_INVALID_TYPE;

            bType = t_p;

            if( vVal._str )
            {
                string *pXOBJ = NULL;
                iRet = pRuntime->createXObject( *pSymType, NULL, (xobject**)&pXOBJ );
                if( iRet == XORT_OK )
                {
                    pXOBJ->Assign( vVal._str );
                    SetValue( pXOBJ );
                    pXOBJ->Release();
                }
            }
        }
        break;

    case xni_bin:
        {
            if( pSymType->m_dwTemplateType != t_array && ( pSymType->m_dwTemplSpecType != t_u1 || pSymType->m_dwTemplSpecType != t_s1 ) )
                return ERR_INVALID_TYPE;

            bType = t_p;

            if( vVal._bin && vVal.dwSize )
            {
                ByteArray *pObj = NULL;
                iRet = pRuntime->createXObject( *pSymType, NULL, (xobject**)&pObj );
                if( iRet == XORT_OK )
                {
                    dword dwRet = pObj->reserve( vVal.dwSize );
                    if( dwRet != vVal.dwSize )
                        return ERR_MEMORY_ALLOCATION;

                    memcpy( pObj->ptr( 0 ), vVal._bin, vVal.dwSize );

                    pObj->set_itemsCount( vVal.dwSize );
                }
            }
        }
        break;

    default:
        return ERR_INTERNAL;
    }

    bAccess = usr_VarRW;

    return iRet;
}

int XortElement::CopyToXNIVariant( XNIVariant& vVal, symbolref pSymType ) const
{
    int iRet = XORT_OK;

    switch( bType )
    {
    case t_v:
    case t_s1:
    case t_u1:
    case t_s2:
    case t_u2:
    case t_s4:
    case t_u4:
    case t_s8:
    case t_u8:
    case t_r4:
    case t_r8:
        vVal.bType = bType;
        vVal._u8 = _u8;
        break;

    case t_p:
        if( _p )
        {
            if( pSymType->m_dwType == t_string )
            {
                string *pStr = (string *)_p;

                vVal.bType = xni_str;
                vVal.dwSize = pStr->Length() + 1;
                vVal._str = new char [ vVal.dwSize ];
                if( !vVal._str )
                    return ERR_MEMORY_ALLOCATION;

                strcpy( vVal._str, pStr->GetBuffer() );
            }
            else if( pSymType->m_dwTemplateType == t_array && ( pSymType->m_dwTemplSpecType == t_s1 || pSymType->m_dwTemplSpecType == t_u1 ) )
            {
                ByteArray *pArr = (ByteArray *)_p;

                vVal.bType = xni_bin;
                vVal.dwSize = pArr->count();
                vVal._bin = new byte [ vVal.dwSize ];
                if( !vVal._bin )
                    return ERR_MEMORY_ALLOCATION;

                memcpy( vVal._bin, pArr->ptr( 0 ), pArr->count() );

            } else {
                iRet = ERR_UNSUPPORTED_TYPE_FOR_NATIVE_CALL;
            }
        } else {
            iRet = ERR_NULL_PTR;
        }
        break;

    default:
        return ERR_UNKNOWN_TYPE;
    }

    return iRet;
}
